use super::{HttpControlStop, HttpHandle};
use crate::app::core::{EntryPointServer, OptResponse};
use crate::config::EntryPoint;
use anyhow::Result;
use hyper::service::Service;
use hyper::{Body, Error, Request, Response};
use std::future::Future;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;

pub struct HttpServer {
    ep: EntryPoint,
    handles: Vec<Arc<dyn HttpHandle + 'static>>,
    status: Arc<AtomicBool>,
}
impl HttpServer {
    pub fn new(ep: EntryPoint) -> (HttpServer, HttpServerStop) {
        let handles = vec![];
        let status = Arc::new(AtomicBool::new(true));
        let hss = HttpServerStop {
            status: status.clone(),
        };
        let hs = Self {
            ep,
            handles,
            status,
        };
        (hs, hss)
    }
    #[allow(dead_code)]
    pub fn register_handle<T>(mut self, handle: T) -> Self
    where
        T: HttpHandle + 'static,
    {
        self.handles.push(Arc::new(handle));
        self
    }
    async fn wait_shout_down(&self) {
        loop {
            if self.status.load(Ordering::Relaxed) {
                tokio::time::sleep(Duration::from_millis(10)).await;
            } else {
                break;
            }
        }
        wd_log::log_info_ln!("入口服务{} 开始关闭...", self.ep.name);
    }
}
#[async_trait::async_trait]
impl EntryPointServer for HttpServer {
    async fn run(&mut self) -> Result<()> {
        wd_log::log_info_ln!("运行http服务：{}", serde_json::to_string(&self.ep).unwrap());
        let addr = self.ep.addr.parse()?;
        let server = hyper::Server::bind(&addr)
            .serve(MakeSvc::new(self.ep.clone()).register_handles(self.handles.clone()));
        let server = server.with_graceful_shutdown(self.wait_shout_down());
        if let Err(e) = server.await {
            wd_log::log_error_ln!("http运行出错：{}", e.to_string());
        }
        self.status.store(true, Ordering::Relaxed);
        Ok(())
    }
}

struct MakeSvc {
    ep: EntryPoint,
    handles: Vec<Arc<dyn HttpHandle + 'static>>,
}
impl MakeSvc {
    fn new(ep: EntryPoint) -> Self {
        let handles = vec![];
        Self { ep, handles }
    }
    fn register_handles(mut self, handles: Vec<Arc<dyn HttpHandle + 'static>>) -> Self {
        self.handles = handles;
        self
    }
    fn http_service(&mut self) -> HttpService {
        let name = self.ep.name.clone();
        let handles = self.handles.clone();
        HttpService { name, handles }
    }
}

#[derive(Clone)]
struct HttpService {
    name: String,
    handles: Vec<Arc<dyn HttpHandle + 'static>>,
}

impl<T> Service<T> for MakeSvc {
    type Response = HttpService;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
    fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, _: T) -> Self::Future {
        let counter = self.http_service();
        let fut = async move { Ok(counter) };
        Box::pin(fut)
        // (self.call_service())(t)
    }
}

impl Service<Request<Body>> for HttpService {
    type Response = Response<Body>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }
    fn call(&mut self, mut req: Request<Body>) -> Self::Future {
        let name = self.name.clone();
        let handles = self.handles.clone();

        Box::pin(async move {
            let ctx = wd_run::Context::new();
            ctx.set("application_name", name).await;
            let mut resp = None;
            let mut eldnah = vec![];
            for handle in handles.into_iter() {
                eldnah.insert(0, handle);
                match eldnah[0].request(ctx.clone(), req).await {
                    Ok(o) => {
                        req = o;
                    }
                    Err(r) => {
                        resp = Some(r);
                        break;
                    }
                }
            }
            for handle in eldnah.into_iter() {
                let r = handle.response(ctx.clone(), resp.unwrap()).await;
                resp = Some(r);
            }
            Ok(resp.unwrap())
        })
    }
    // fn call(&mut self, req: Request<Body>) -> Self::Future {
    //     let name = self.name.clone();
    //     Box::pin(async move {
    //         let method = req.method().to_string();
    //         let url = req.uri().to_string();
    //         let version = req.version();
    //         let resp = Response::builder()
    //             .status(200)
    //             .body(Body::from(format!(
    //                 "{} ::: version[{:?}] method[{}] ===>url:{}",
    //                 name, version, method, url
    //             )))
    //             .unwrap_or(Response::default());
    //         Ok(resp)
    //     })
    // }
}

pub struct HttpServerStop {
    status: Arc<AtomicBool>,
}
#[async_trait::async_trait]
impl HttpControlStop for HttpServerStop {
    async fn stop(&mut self, ot: wd_run::Context) -> Result<Option<OptResponse>> {
        let timeout = ot
            .get::<_, Duration>("stop_timeout")
            .await
            .unwrap_or(Arc::new(Duration::from_secs(3)));
        let timeout = timeout.deref().clone();
        self.status.store(false, Ordering::Relaxed);
        tokio::time::timeout(timeout, async move {
            for _ in 0..3000 {
                if self.status.load(Ordering::Relaxed) {
                    break;
                }
                tokio::time::sleep(Duration::from_millis(10)).await;
            }
        })
        .await?;
        Ok(None)
    }
}
